from fastapi import Request
import json
from app.schemas.response import success, fail
from fastapi.responses import JSONResponse
import time
from app.core.logger import logger
from app.core.security import get_user_id_from_token
from app.models.api_log import ApiLog
import asyncio
from app.core.session import async_db_session
from fastapi.exceptions import HTTPException
from app.core.logger import TraceID


# 排除文档路径
EXCLUDE_PATHS = ("/docs", "/redoc", "/openapi.json", "/favicon.ico")

async def response_wrapper(request: Request, call_next):
    # 设置日志的全链路追踪
    REQUEST_ID_KEY = "X-Request-Id"
    _req_id_val = request.headers.get(REQUEST_ID_KEY, "")
    req_id = TraceID.set(_req_id_val)

    # 记录请求日志
    logger.info(f"Request: {request.method} {request.url.path}")
    # 排除文档路径
    if request.url.path.endswith(EXCLUDE_PATHS):
        # 不记录 Swagger 和 OpenAPI 请求
        return await call_next(request)
    
    # 处理fanctory响应
    response = await call_next(request)
    start_time = time.time()
    process_time = time.time() - start_time
    # 添加处理时间头到响应中
    response.headers["X-Process-Time"] = str(process_time)
    # 添加请求ID头到响应中
    response.headers[REQUEST_ID_KEY] = req_id

    # 解析请求体
    try:
        request_body = await request.body()
        request_body = request_body.decode() if request_body else "<non-readable body>"
    except Exception:
        request_body = "<non-readable body>"

    # 处理JSON响应
    # try:
    #     logger.info(f"Response: {response.status_code} {response.headers}")
    #     # 提取响应内容
    #     body_bytes = b"".join([chunk async for chunk in response.body_iterator])
    #     response.body_iterator = iter([body_bytes])
    #     response_body = body_bytes.decode("utf-8")
    #     data = json.loads(response_body)
    #     code = data.get("code", response.status_code)
    # except Exception:
    #     code = response.status_code
    
    # 从请求头中提取用户ID（根据JWT Token）
    # user_id = await get_user_id_from_token(request)
    # 异步写入日志
    # asyncio.create_task(
    #     write_log_to_db(
    #         user_id=user_id,
    #         path=request.url.path,
    #         method=request.method,
    #         status_code=code,
    #         process_time=process_time,
    #         request_body=request_body,
    #         response_body=response_body,
    #         ip_address=request.client.host
    #     )
    # )

    # 处理成功响应（JSON格式）
    if response.status_code == 200 and response.headers.get("Content-Type", "").startswith("application/json"):
        try:
            body = b""
            async for chunk in response.body_iterator:
                body += chunk
            data = json.loads(body)

            # 如果不是标准格式，则包装
            if not isinstance(data, dict) or "code" not in data:
                # code 为 0 时，包装为标准格式
                data = success(data)
                logger.info(f"Response body: {data}")

                # 让 Swagger 仍能识别 token（仅在 /login 接口）
                if request.url.path.endswith("/login"):
                    data["access_token"] = data["data"]["access_token"]
                    data["token_type"] = data["data"]["token_type"]

            return JSONResponse(content=data, status_code=200)
        except json.JSONDecodeError as e:
            # 如果解析失败，返回原始响应
            logger.error(f"[response_wrapper_middleware] 解析异常: {e}")
            return response
    # else:
    #     # 其他错误状态码，包装为标准格式
    #     return JSONResponse(fail(msg=response.error.detail,code=response.status_code), status_code=200)
    return response

async def write_log_to_db(user_id, path, method, status_code, process_time, request_body, response_body, ip_address):
    """
    异步写入日志到数据库
    """
    logger.info(f"Writing log to DB: {user_id, path, method, status_code, process_time, request_body, response_body, ip_address}")  
    try:
        # 这里直接调用 async_db_session() 来创建异步会话
        # 不能使用 get_user_db() 来创建会话，因为yield只能用于 FastAPI 路由依赖中，不能在中间件里直接使用
        async with async_db_session() as session:
            apiLog = ApiLog(
                uid=user_id,
                path=path,
                method=method,
                status_code=status_code,
                process_time=process_time,
                request_body=request_body,
                response_body=response_body,
                ip_address=ip_address
            )
            session.add(apiLog)
            await session.commit()
    except Exception as e:
        logger.error(f"[write_log_to_db] 写入数据库日志失败: {e}")